/*******************************************************************************
 *                                    ZLG
 *                         ----------------------------
 *                         innovating embedded platform
 *
 * Copyright (c) 2001-present Guangzhou ZHIYUAN Electronics Co., Ltd.
 * All rights reserved.
 *
 * Contact information:
 * web site:    https://www.zlg.cn
 *******************************************************************************/
/*******************************************************************************
 * Includes
 ******************************************************************************/
#include "hpm6e00_otp.h"

/*******************************************************************************
 * Code
 ******************************************************************************/
/**
 * \brief OTP 字读函数
 *
 * \param[in]  addr   读地址
 * \param[out] p_data 返回读到的数据
 *
 * \retval 成功返回 0
 */
int otp_word_read(uint32_t addr, uint32_t *p_data){
    uint32_t time_out = 5000;

    if ((addr > OTP_WORDS_MAX - 1) || (p_data == NULL)) {
        return -EINVAL;
    }

    WRITE_REG32(HPM_OTP->addr, addr);
    WRITE_REG32(HPM_OTP->int_flag, OTP_INT_FLAG_READ_MASK);
    WRITE_REG32(HPM_OTP->cmd, OTP_CMD_READ);

    while((--time_out) && (!(READ_REG32(HPM_OTP->int_flag) & OTP_INT_FLAG_READ_MASK)));
    if (time_out == 0) {
        return -ETIME;
    }
    *p_data = READ_REG32(HPM_OTP->data);

    return 0;
}

/**
 * \brief OTP 字编程函数
 *
 * \param[in] addr    写地址
 * \param[in] p_data  要写的字数据缓存
 * \param[in] n_words 字数量
 *
 * \retval 成功返回 0
 */
int otp_words_program(uint32_t addr, uint32_t *p_data, uint32_t n_words){
    uint32_t i, tmp, time_out = 5000;
    uint32_t fuse_idx_max     = NELEMENTS(HPM_OTP->shadow);

    if ((addr >= fuse_idx_max) ||
            (n_words > fuse_idx_max) ||
            (addr + n_words > fuse_idx_max) ||
            (p_data == NULL)) {
        return -EINVAL;
    }

    tmp  = READ_REG32(HPM_PCFG->LDO2P5) & ~PCFG_LDO2P5_VOLT_MASK;
    tmp |= PCFG_LDO2P5_ENABLE_MASK | (2500);
    WRITE_REG32(HPM_PCFG->LDO2P5, tmp);

    clk_cpu_delay_ms(1);

    for (i = 0; i < n_words; i++) {
        WRITE_REG32(HPM_OTP->unlock, OTP_UNLOCK_MAGIC_NUM);
        WRITE_REG32(HPM_OTP->addr, addr);
        WRITE_REG32(HPM_OTP->data, *p_data);
        WRITE_REG32(HPM_OTP->int_flag, OTP_INT_FLAG_WRITE_MASK);
        WRITE_REG32(HPM_OTP->cmd, OTP_CMD_PROGRAM);

        while((--time_out) && (!(READ_REG32(HPM_OTP->int_flag) & OTP_INT_FLAG_WRITE_MASK)));
        if (time_out == 0) {
            return -ETIME;
        }
        addr++;
        p_data++;
        time_out = 5000;
    }

    CLEAR_REG32_BIT(HPM_PCFG->LDO2P5, PCFG_LDO2P5_ENABLE_MASK);

    return 0;
}
